﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Validation;

namespace CRM.Database.Model
{
    /// <summary>
    /// Абстрактный класс для всех коллекций
    /// </summary>
    public abstract class AbstractCollection : IGetItem, IAddDeleteUpdate, IGetList, IGetIdByName, IGetStaticCollection
    {
        #region IGetIdByName Members

        /// <summary>
        /// Получение идентификатора по имени
        /// </summary>
        /// <param name="name">Имя</param>
        /// <returns>Идентификатор</returns>
        public int GetIdByName(string name)
        {
            foreach (object item in GetList())
            {
                var getNamesInterface = item as IGetNamesValues;
                if (getNamesInterface == null)
                {
                    throw new Exception("Необходимо реализовать метод получения списка имён");
                }

                if (getNamesInterface == null)
                    return 0;
                foreach (string Name in getNamesInterface.GetNamesValues())
                {
                    if (Name == name)
                    {
                        var getKeyValueInterface = item as IGetKeyValue;

                        if (getKeyValueInterface == null)
                            throw new Exception("Необходимо реализовать метод получения ключевого значения");
                        return getKeyValueInterface.GetKeyValue();
                    }
                }
            }
            return 0;
        }

        #endregion

        #region IGetList Members

        /// <summary>
        /// Получение списка элементов
        /// </summary>
        /// <returns>Список элементов</returns>
        public abstract List<object> GetList();

        #endregion


        /// <summary>
        /// Текущая база данных
        /// </summary>
        public string CurrentDatabase
        {
            get
            {
                if(Entities!=null)
                    if(Entities.Database!=null)
                        if (Entities.Database.Connection!=null)
                            if (Entities.Database.Connection.Database!=null)
                                return Entities.Database.Connection.Database;
                return "unknown db";
            }
        }

        private  CRMEntities _crmEntities;

        /// <summary>
        /// Ссылка на контекст
        /// </summary>
        public CRMEntities Entities
        {
            get
            {
                if (_crmEntities == null)
                    _crmEntities = new CRMEntities();
                
                return _crmEntities;
            }
        }

        /// <summary>
        /// Получение объекта по имени
        /// </summary>
        /// <param name="name">Имя объекта</param>
        /// <returns>Объект</returns>
        public object GetItemByName(string name)
        {
            int id = GetIdByName(name);
            if (id == 0)
                return null;
            return GetItemById(id);
        }

        /// <summary>
        /// Получение списка элементов по названию
        /// </summary>
        /// <param name="name">Название</param>
        /// <returns>Список элементов</returns>
        public List<object> GetItemsListByName(string name)
        {
            var result = new List<object>();
            foreach (object item in GetList())
            {
                var getNamesInterface = item as IGetNamesValues;
                if (getNamesInterface == null)
                {
                    throw new Exception("Необходимо реализовать метод получения списка имён");
                }
               
                foreach (string Name in getNamesInterface.GetNamesValues())
                {
                    if (Name.Trim().ToUpper() == name.Trim().ToUpper())
                    {
                      if(!result.Contains(item))
                          result.Add(item);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Обладает ли элемент тем же типом, что и коллекция
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <returns>Результат</returns>
        protected bool IsTheSameType(object item)
        {
            //if (item.GetType().GUID != GetType().GUID)
            //    return false;
            return true;
        }

        /// <summary>
        /// Получение типа текущего элемента
        /// </summary>
        /// <returns></returns>
        protected abstract Type GetItemType();

        #region Implementation of IGetStaticCollection

        /// <summary>
        /// Получение статического списка для хранения объектов
        /// </summary>
        /// <returns></returns>
        public abstract object GetStaticCollection();

        #endregion

        #region Implementation of IGetItem

        ///// <summary>
        ///// Получение элемента из коллекции по идентификатору
        ///// </summary>
        ///// <param name="itemId">Идентификатор</param>
        ///// <returns>Элемент</returns>
        //public object GetItemById(int itemId)
        //{
        //    foreach (object item in GetList())
        //    {
        //        var getKeyValueInterface = item as IGetKeyValue;

        //        if (getKeyValueInterface == null)
        //            throw new Exception("Необходимо реализовать метод получения ключевого значения");
        //        if (getKeyValueInterface.GetKeyValue() == itemId)
        //        {
        //            return item;
        //        }
        //    }
        //    return null;
        //}


        /// <summary>
        /// Получение элемента из коллекции по идентификатору
        /// </summary>
        /// <param name="itemId">Идентификатор</param>
        /// <returns>Элемент</returns>
        public abstract object GetItemById(int itemId);

        /// <summary>
        /// Получение элемента из коллекции по идентификатору
        /// </summary>
        /// <param name="itemId">Идентификатор</param>
        /// <returns>Элемент</returns>
        public object GetItemByIdFromDatabase(int itemId)
        {
            return GetItemById(itemId);
        }

        #endregion

        #region Implementation of IAddDeleteUpdate

        /// <summary>
        /// Добавление элемента в коллекцию
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <param name="userLogin">Логин пользователя, который делает изменения</param>
        public bool Add(object item, string userLogin)
        {
            if (IsTheSameType(item))
            {
                Entities.Configuration.AutoDetectChangesEnabled = false;
                SetChangedUser(item, userLogin);

                Entities.Entry(item).State = EntityState.Added;
                Entities.Configuration.AutoDetectChangesEnabled = true;
                return Save();
            }
            return false;
        }


     

        /// <summary>
        /// Удаление элемента из коллекции
        /// </summary>
        /// <param name="item">Элемент</param>
        /// <returns>Результат удаления</returns>
        public bool Delete(object item)
        {
            if (IsTheSameType(item))
            {

                var GetKeyValueinterface = item as IGetKeyValue;
                var obj = GetItemById(GetKeyValueinterface.GetKeyValue());
                Entities.Configuration.AutoDetectChangesEnabled = false;
                Entities.Entry(obj).State = EntityState.Deleted;
                Entities.Configuration.AutoDetectChangesEnabled = true;
                return Save();
            }
            return false;
        }


        /// <summary>
        /// Удаление элемента из коллеции по идентификатору
        /// </summary>
        /// <param name="itemId">Идентификатор</param>
        /// <returns>Результат удаления</returns>
        public bool DeleteById(int itemId)
        {
            object obj = GetItemById(itemId);
            return obj != null && Delete(obj);
        }

        /// <summary>
        /// Обновление элемента в коллекции
        /// </summary>
        /// <param name="item">Новый элемент</param>
        /// <param name="userLogin">Логин пользователя, который делает изменения</param>
        /// <returns>Результат операции</returns>
        public bool Update(object item, string userLogin, bool save=true)
        {
            var getKeyValueinterface = item as IGetKeyValue;
            if (getKeyValueinterface != null)
            {
                var obj = GetItemById(getKeyValueinterface.GetKeyValue());
                SetChangedUser(obj, userLogin);
                Entities.Configuration.AutoDetectChangesEnabled = false;

                Entities.Entry(obj).State = EntityState.Modified;
                Entities.Configuration.AutoDetectChangesEnabled = true;
              if(save)  return Save();
                return true;
            }
            return false;
        }


        /// <summary>
        /// Обновление элемента в коллекции
        /// </summary>
        /// <param name="item">Новый элемент</param>
        /// <param name="userLogin">Логин пользователя, который делает изменения</param>
        /// <returns>Результат операции</returns>
        public bool Update(object item, string userLogin)
        {
            var getKeyValueinterface = item as IGetKeyValue;
            if (getKeyValueinterface != null)
            {
                var obj = GetItemById(getKeyValueinterface.GetKeyValue());
                SetChangedUser(obj, userLogin);
                Entities.Configuration.AutoDetectChangesEnabled = false;

                Entities.Entry(obj).State = EntityState.Modified;
                Entities.Configuration.AutoDetectChangesEnabled = true;
                return Save();
                
            }
            return false;
        }

        /// <summary>
        /// Сохранение изменений
        /// </summary>
        /// <returns></returns>
        public  bool Save()
        {
            try
            {
               Entities.SaveChanges();
            }
                //catch(DbEntityValidationException e)
                //{
                    
                //}
            catch (Exception e)
            {
                return false;
            }

          

            return true;
        }

        /// <summary>
        /// Обнуление статической коллекции
        /// </summary>
        protected abstract void SetStaticListToNULL();




        #endregion



        /// <summary>
        /// Установка пользователя, который внёс изменения
        /// </summary>
        /// <param name="item">Измененённый элемент</param>
        /// <param name="userLogin">Пользователь</param>
        internal static void SetChangedUser(object item, string userLogin)
        {
            var setChangedUserInterface = item as ISetChangedUser;

            if (setChangedUserInterface != null)
            {
                setChangedUserInterface.SetChangedUser(userLogin);
            }
        }
    }
}